package com.googlecode.lohr.tools.compiler;

import java.io.File;
import java.io.IOException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import com.googlecode.lingwah.grammars.ALFGrammar;
import com.googlecode.lohr.parser.combinators.MatchResults;
import com.googlecode.lohr.parser.combinators.Matcher;
import com.googlecode.lohr.parser.combinators.node.Match;
import com.googlecode.lohr.parser.combinators.node.MatchNavigation;
import com.googlecode.lohr.utils.IOUtils;
import com.googlecode.lohr.utils.SystemUtils;

/**
 * Compiles Lohr documents to RDF/XML (.rdf) model files.
 * 
 * @usage
 *  LohrModelCompiler [ options ] [ sourcefiles ] [ argfile ]
 *  
 *		options
 *			Command-line options.
 *		sourcefiles
 *			One or more Lohr source files to be compiled (such as MyClass.lohr).
 *			Separated by semicolons
 *		argfile
 *			file that lists options and source files. 
 *
 * @author Ted Stockwell
 */
public class LohrModelCompiler {
	
	public static final String MODELS= "-models";
	public static final String DEST= "-dest";
	public static final String TASKS= "-tasks";
	public static final String SOURCES= "-sources";
	
	
	public static void main(String[] args) {
		new LohrModelCompiler().runFromCommandLine(args);
	}
	
	private List<File> sources= new ArrayList<File>();
	private File destFolder;


	public void runFromCommandLine(String[] sargs) {
		Map<String,String> args= SystemUtils.parseArgs(sargs);
		
		String sources= args.get(SOURCES);
		if (sources == null) 
			error("-sources option not specified");
		parseSourcePath(sources);

		String dest= args.get(DEST);
		if (dest == null) 
			error("-dest option not specified");
		destFolder= new File(dest);
		if (!destFolder.exists())
			if (!destFolder.mkdirs())
				error("Could not create destination folder:"+destFolder);
		
		runCompilationTask();
	}

	protected void runCompilationTask() {
		for (File source: sources) {
			try {
				compileSource(source);
			} catch (IOException e) {
				System.out.printf("Skipping "+source+".  Error reading file. "+e.getMessage());
				System.out.printf(SystemUtils.getStackTrace(e));
			}
		}
	}

	protected void compileSource(File source) 
	throws IOException 
	{
		// parse source file
		String contents= new String(IOUtils.readFully(source), "UTF-8");
		MatchResults matchResults= ALFGrammar.getMatcher().match(contents);
		if (!matchResults.success()) 
			throw new RuntimeException("Error parsing file. "+matchResults.errorMsg+" at position "+matchResults.position);
		
		// choose the longest match
		Match root= matchResults.matches.get(0);
		if (1 < matchResults.matches.size()) {
			for (Match n: matchResults.matches) {
				if (root.length() < n.length()) 
					root= n;
			}
		}
		
		
		String destName= source.getName();
		destName= destName.substring(0, destName.indexOf('.'))+".rdf";
		File destFile= new File(destFolder, destName);
		
		root.accept(new LohrRDFCreator(destFile));
	}
	
	
	protected void parseSourcePath(String sources) {
		String[] pathnames= sources.split(";");
		for (String pathname:pathnames) {
			File file= new File(pathname);
			if (!file.exists()) {
				System.out.printf("Skipping "+pathname+".  File does not exist.");
				continue;
			}
			if (file.isDirectory()) {
				ArrayList<File> todo= new ArrayList<File>();
				todo.add(file);
				while (!todo.isEmpty()) {
					File dir= todo.remove(0);
					for (File child:dir.listFiles()) {
						if (child.isDirectory()) {
							todo.add(child);
							continue;
						}
						if (!child.getName().endsWith(".lohr")) 
							continue;
						this.sources.add(child);
					}
				}
				continue;
			}
			this.sources.add(file);
		}
	}

	void error(String message) {
		System.err.println(message);
		printUsage();
	}
	void printUsage() {
		System.out.println("Usage:");
		System.out.println("LohrModelCompiler options [ tasks ]");
		System.out.println("options:" );
		System.out.println("  -sources: semicolon delimited list of files and/or folder to compile" );
		System.out.println("  -models: A semicolon delimited list of folder names where .rdf model files are stored" );
		System.out.println("  -dest: destination directory for newly compiled model files" );
		System.out.println("  -tasks: specifies file(s) that lists options and source files" );
		System.exit(1);
	}
}